# -*- coding:utf-8 -*-
import datetime
from flask import request, g, jsonify, current_app, session
from Ihome.models import Area, Facility, House, HouseImage,Order
from . import api
from Ihome.utils.response_code import RET
from Ihome import redis_store, db
from Ihome.constants import HOME_PAGE_MAX_HOUSES, HOUSE_DETAIL_REDIS_EXPIRE_SECOND, AREA_INFO_REDIS_EXPIRES, \
    QINIU_DOMIN_PREFIX, HOUSE_LIST_PAGE_CAPACITY
from Ihome.constants import HOME_PAGE_DATA_REDIS_EXPIRES
from Ihome.utils.common import login_required
from Ihome.utils.storage_image import stroage_image
from Ihome import constants

@api.route('/houses')
def search_house():
    '''
    var params = {
        aid:areaId,
        sd:startDate,
        ed:endDate,
        sk:sortKey,
        p:next_page
    };
    :return:
    '''
    args = request.args
    # 区域的id
    aid = args.get('aid', '')
    # 用户过滤的开始入住日期和结束入住日期
    start_date_str = args.get('sd', '')  # 开始日期
    end_date_str = args.get('ed', '')  # 结束日期
    # new最新上线,booking入住最多,price-inc价格 低>高, pirce-des 价格 高>低
    sk = args.get('sk', 'new')  # 排序方式
    p = args.get('p', '1')  # 页码
    # print start_date_str,end_date_str,type(start_date_str)
    #判断参数
    start_date=None
    end_date=None
    try:
        #start 2017-12-15 end 2017-12-11
        if start_date_str:
            start_date=datetime.datetime.strptime(start_date_str,'%Y-%m-%d')
        if end_date_str:
            end_date=datetime.datetime.strptime(end_date_str,'%Y-%m-%d')
            # print start_date, end_date,type(start_date)
        if start_date and end_date:
            assert start_date <end_date,Exception('开始时间不能大于结束时间')
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR,errmsg='参数有误')

    try:
        p=int(p)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR,errmsg='参数有误')

    # 从redis中读取房屋数据
    try:
        redis_key = 'house_list_%s_%s_%s_%s'%(aid,start_date_str,end_date_str,sk)
        response_dict = redis_store.hget(redis_key,p)
    except Exception as e:
        current_app.logger.error(e)

    # 先把所有的房屋都查询出来并返回
    try:
        # houses=House.query.all()
        house_query = House.query
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据查询失败')

    # 过滤条件的列表
    # filters=None
    filters = []
    if aid:
        # 添加过滤条件
        filters.append(House.area_id == aid)
        # filters = (House.area_id == aid)
    '''
    Order.begin_date < end_date and Order.end_date > start_date
    所以要查询出所有的冲突的订单
    取到这些冲突订单的房屋id > [1,4,7]
    去房屋表中查:不包含冲突订单的房屋id的数据 House.query.filter(House.id.notin_([1,4,7]))
    '''
    #定义冲突的订单
    conflict_order = None
    if start_date and end_date:
        conflict_order = Order.query.filter(Order.begin_date < end_date, Order.end_date > start_date).all()
    elif start_date:
        conflict_order = Order.query.filter(Order.end_date > start_date).all()
    elif end_date:
        conflict_order = Order.query.filter(Order.begin_date < end_date).all()

    if conflict_order:
        #取到这些冲突订单的房屋id > [1,4,7]
        conflict_house_ids = [order.house_id for order in conflict_order]
        # 不包含冲突订单的房屋id数据
        filters.append(House.id.notin_(conflict_house_ids))

    # 根据不同排序方式查询
    if sk == 'booking':
        house_query = house_query.filter(*filters).order_by(House.order_count.desc())
    elif sk == 'price-inc':  # 价格从低到高
        house_query = house_query.filter(*filters).order_by(House.price)
    elif sk == 'price-des':  # 价格从高到低
        house_query = house_query.filter(*filters).order_by(House.price.desc())
    else:
        house_query = house_query.filter(*filters).order_by(House.create_time.desc())
    # 获取到分页对象:参数1 :第几页数据,参数2:每页有多少个,参数3是否输出错误
    paginate = house_query.paginate(int(p), HOUSE_LIST_PAGE_CAPACITY, False)
    # 取到当前页的所有对象
    houses = paginate.items
    # 记录总页数
    total_page = paginate.pages

    houses_dict = []
    for house in houses:
        houses_dict.append(house.to_basic_dict())

    response_dict={'houses':houses_dict,'total_page':total_page}

    #保存房屋数据
    if p <= total_page:#当前页如果小于或等于总页数,再去存
        try:
            redis_key = 'house_list_%s_%s_%s_%s'%(aid,start_date_str,end_date_str,sk)
            #获取到管道操作,redis事务
            pipe = redis_store.pipeline()
            #开启事务
            pipe.multi()
            #设置数据
            pipe.hset(redis_key,p,response_dict)
            #设置指定key的过期时间
            pipe.expire(redis_key,constants.HOUSE_LIST_REDIS_EXPIRES)
            #提交事务
            pipe.execute()
        except Exception as e:
            current_app.logger.error(e)

    return jsonify(errno=RET.OK, errmsg='OK', data={'houses': houses_dict, 'total_page': total_page})


@api.route('/houses/index')
def get_houses_index():
    '''
    首页推荐房屋最多5个,以订单数量来排序(倒序）
    :return:
    '''
    try:
        houses_dict = redis_store.get('home_house_index')
        if houses_dict:
            return jsonify(errno=RET.OK, errmsg='ok', data=eval(houses_dict))
    except Exception as e:
        current_app.logger.error(e)

    # 查询房屋数据:以订单号倒序排序,最前5个
    try:
        houses = House.query.order_by(House.order_count.desc()).limit(HOME_PAGE_MAX_HOUSES).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据失败')

    houses_dict = []
    if houses:
        for house in houses:
            houses_dict.append(house.to_basic_dict())

        # 缓存数据
        try:
            redis_store.set('home_house_index', houses_dict, HOME_PAGE_DATA_REDIS_EXPIRES)
        except Exception as e:
            current_app.logger.error(e)
        return jsonify(errno=RET.OK, errmsg='OK', data=houses_dict)

    return jsonify(errno=RET.OK, errmsg='OK', data=houses_dict)


@api.route('/house/<int:house_id>')
def get_house_detail(house_id):
    '''
    1 通过house_id查询出房屋
    2 将房屋模型的数据封装到字典中,user_id(取到当前登录用户的id,如果用户没有登陆,值为-1表示未登录)
    3 直接返回
    4 将房屋数据缓存到redis中
    :param house_id:
    :return:
    '''

    user_id = session.get('user_id')
    # 去读取
    try:
        house_dict = redis_store.get('house_deatil_%d' % house_id)
        if house_dict:
            return jsonify(errno=RET.OK, errmsg='OK', data={'user_id': user_id, 'house': eval(house_dict)})
    except Exception as e:
        current_app.logger.error(e)

    # 通过房屋id查找到具体的房屋信息
    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据查询失败')

    if not house:
        return jsonify(errno=RET.NODATA, errmsg='房屋不存在')

    # 生成要返回的信息
    house_dict = house.to_full_dict()
    # 去缓存
    try:
        redis_store.set('house_deatil_%d' % house_id, house_dict, HOUSE_DETAIL_REDIS_EXPIRE_SECOND)
    except Exception as e:
        current_app.logger.error(e)

    return jsonify(errno=RET.OK, errmsg='OK', data={'user_id': user_id, 'house': house_dict})


@api.route('/houses/<int:house_id>/images', methods=['POST'])
@login_required
def upload_house_image(house_id):
    '''
    1 取到参数,house_id,要上传的图片
    2 查询对应的id的房屋
    3 在上传图片
    4 保存图片,判断房屋的首页图片是否有值,如果没有值,设置
    :param house_id:
    :return:
    '''

    try:
        house_image_file = request.files.get('house_image').read()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    # 2 查询是否指定房屋
    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmssg='上传图片失效')

    if not house:
        return jsonify(errno=RET.NODATA, errmsg='房屋信息不存在')

    # 3 再上传图片
    try:
        url = stroage_image(house_image_file)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg='上传图片失败')

    # 4 初始化模型
    house_image = HouseImage()
    house_image.house_id = house.id
    house_image.url = url

    try:
        # 设置房屋的头图
        if not house.index_image_url:
            house.index_image_url = url
        db.session.add(house_image)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='保存图片数据失败')

    return jsonify(errno=RET.OK, errmsg='OK', data={'url': QINIU_DOMIN_PREFIX + url})


@api.route('/house', methods=['POST'])
@login_required
def save_new_house():
    '''
    1 获取上传的参数
    2 判断是否为空,校验参数
    3 初始化一个House的对象
    4 进行数据保存
    5 返回结果
    {
    'title':'1',
    'price':'1',
    'area_id':'1',
    'address':'1',
    'room_count':'1',
    'acreage':'1',
    'unit':'1',
    'capacity':'1',
    'beds':'1',
    'deposit':'1',
    'min_days':'1',
    'max_days':'0',
    'facility':['1','2','4'],
    :return:
    '''

    # 1 获取上传的参数
    user_id = g.user_id
    json_dict = request.json
    title = json_dict.get('title')
    price = json_dict.get('price')
    area_id = json_dict.get('area_id')
    address = json_dict.get('address')
    room_count = json_dict.get('room_count')
    acreage = json_dict.get('acreage')
    unit = json_dict.get('unit')
    capacity = json_dict.get('capacity')
    beds = json_dict.get('beds')
    deposit = json_dict.get('deposit')
    min_days = json_dict.get('title')
    max_days = json_dict.get('title')

    # 2 判断是否为空,校验参数
    if not all([acreage, max_days, min_days, deposit, beds, unit, capacity, address, room_count, title, area_id]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')
    # 判断传入的金额是否是数字, 将其转成以分为单位的
    try:
        price = int(float(price) * 100)
        deposit = int(float(deposit) * 100)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')

    # 3 初始化house对象
    house = House()

    house.user_id = user_id
    house.area_id = area_id
    house.title = title
    house.price = price
    house.address = address
    house.room_count = room_count
    house.acreage = acreage
    house.unit = unit
    house.capacity = capacity
    house.beds = beds
    house.deposit = deposit
    house.min_days = min_days
    house.max_days = max_days

    # 设置房屋设施
    facilities = json_dict.get('facility')
    if facilities:
        # 查询指定列表中对应的模型并设置设施信息
        house.facilities = Facility.query.filter(Facility.id.in_(facilities)).all()

    # 4 进行数据保存
    try:
        db.session.add(house)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='添加数据失败')

    return jsonify(errno=RET.OK, errmsg='OK', data={'house_id': house.id})


@api.route('/areas')
def get_areas():
    '''获取城区信息'''

    # 先从redis中取
    try:
        areas_array = redis_store.get('areas')
        if areas_array:
            return jsonify(errno=RET.OK, errmsg='OK', data={'areas': eval(areas_array)})  # eval这里是转成相应的对象格式
    except Exception as e:
        current_app.logger.error(e)
    # 1 获取所有的城区信息
    areas = Area.query.all()

    # 2 因为areas是一个对象的列表,不能直接返回,需要将其转成字典的列表
    areas_array = []
    for area in areas:
        areas_array.append(area.to_dict())

    # 3 将数据缓存到redis中
    try:
        redis_store.set('areas', areas_array, AREA_INFO_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)

    # 4 数据返回
    return jsonify(errno=RET.OK, errmsg='OK', data={'areas': areas_array})
